/*
 * @Copyright: 2016 www.yyfax.com Inc. All rights reserved.
 */
package com.jaws.core.compatible.service.impl;

import java.io.Serializable;
import java.util.Date;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.danga.MemCached.MemCachedClient;
import com.jaws.core.common.util.JacksonUtil;
import com.jaws.core.compatible.exception.YYRuntimeException;
import com.jaws.core.compatible.service.CacheService;
import com.jaws.core.mvc.exception.RspCodeEnum;

/**
 * Memcached操作入口
 * <p>
 * cache规范:<br>
 * 1.所有cache服务必须设置namespace,不同服务的namespace不能重复;<br>
 * 2.一般针对数据库单表的缓存,所有数据均为 pk --> record; other-index --> pk; list-key --> list-of-pk; <br>
 * </p>
 * 
 * @author jiangmy
 * @date 2016-11-29 10:47:49
 * @since v1.0.0
 */
public class CacheServiceMemcachedImpl implements CacheService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	private String namespace = "DEFAULT.";
	private String split = ".";

	@Resource
	private MemCachedClient memCachedClient;

	/**
	 * 缓存是否启用
	 */
	private boolean on = true;

	/**
	 * 构造函数
	 * 
	 * @param namespace
	 */
	public CacheServiceMemcachedImpl() {
		super();
	}

	public CacheServiceMemcachedImpl(String namespace) {
		super();
		this.namespace = namespace;
	}

	public CacheServiceMemcachedImpl(String namespace, String split) {
		super();
		this.namespace = namespace;
		this.split = split;
	}

	public boolean isOn() {
		return on;
	}

	public void setOn(boolean on) {
		this.on = on;
	}

	/**
	 * key命名空间
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @return
	 */
	@Override
	public String namespacedKey(String key) {
		if (StringUtils.isBlank(key)) {
			throw new YYRuntimeException(RspCodeEnum.COMMON_ERROR_PARAMETER_INVALID, "缓存" + namespace + "的key不能为空");
		}
		if (StringUtils.isBlank(namespace)) {
			return key;
		}
		return namespace.concat(split).concat(key);
	}

	/**
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T extends Serializable> T get(String key) {
		if (!isOn()) {
			logger.debug("缓存未开启: {}", namespace);
			return null;
		}
		key = namespacedKey(key);
		Object object = memCachedClient.get(key);
		try {
			logger.debug("读缓存 {} {}", key, object);
			return object == null ? null : (T) object;
		} catch (ClassCastException e) {
			logger.info("缓存数据类型不符: {}", key);
			delete(key);
			return null;
		}
	}

	/**
	 * 写
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 * @return
	 */
	@Override
	public <T extends Serializable> boolean set(String key, T object) {
		if (object == null) {
			return false;
		}
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key, object);
		return memCachedClient.set(key, object);
	}

	/**
	 * 写
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 * @param seconds
	 */
	@Override
	public <T extends Serializable> boolean set(String key, T object, int seconds) {
		return set(key, object, new Date(seconds * 1000L));
	}

	/**
	 * 写
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 * @param expire
	 */
	@Override
	public <T extends Serializable> boolean set(String key, T object, Date expire) {
		if (object == null) {
			return false;
		}
		key = namespacedKey(key);
		logger.debug("写缓存 {} {} {}", key, object, expire);
		return memCachedClient.set(key, object, expire);
	}

	/**
	 * 删
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @return
	 */
	@Override
	public boolean delete(String key) {
		key = namespacedKey(key);
		logger.debug("删缓存 {} ", key);
		return memCachedClient.delete(key);
	}

	/**
	 * 删多个
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @return
	 * @return
	 */
	@Override
	public int delete(String... keyList) {
		int rs = 0;
		for (String key : keyList) {
			rs += delete(key) ? 1 : 0;
		}
		return rs;
	}

	/**
	 * 增
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 */
	@Override
	public <T extends Serializable> boolean add(String key, T object) {
		key = namespacedKey(key);
		return memCachedClient.add(key, object);
	}

	/**
	 * 增
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 * @param seconds
	 */
	@Override
	public <T extends Serializable> boolean add(String key, T object, int seconds) {
		key = namespacedKey(key);
		return memCachedClient.add(key, object, new Date(seconds * 1000L));
	}

	/**
	 * 增
	 * 
	 * @author jiangmy
	 * @date 2016-11-29 11:23:12
	 * @since v1.0.0
	 * @param key
	 * @param object
	 * @param expire
	 */
	@Override
	public <T extends Serializable> boolean add(String key, T object, Date expire) {
		key = namespacedKey(key);
		return memCachedClient.add(key, object, expire);
	}

	/**
	 * 原子性操作增加并返回增加后的值
	 * 
	 * @author jiangmy
	 * @date 2016-12-08 13:00:33
	 * @param key
	 * @return
	 */
	@Override
	public int incrAndGet(String key) {
		key = namespacedKey(key);
		int i = (int) memCachedClient.incr(key);
		if (i == -1) {
			boolean add = memCachedClient.set(key, "1");
			if (add) {
				i = 1;
			} else {
				throw new YYRuntimeException(RspCodeEnum.COMMON_ERROR_FORMAT_EXCEPTION, "exists key:" + key);
			}
		}
		return i;
	}

	/**
	 * 原子性操作增加并返回增加后的值
	 * 
	 * @author jiangmy
	 * @date 2016-12-08 13:23:04
	 * @param key
	 * @param date
	 * @return
	 */
	@Override
	public int incrAndGet(String key, Date date) {
		key = namespacedKey(key);
		int i = (int) memCachedClient.incr(key);
		if (i == -1) {
			boolean add = memCachedClient.set(key, "1", date);
			if (add) {
				i = 1;
			} else {
				throw new YYRuntimeException(RspCodeEnum.COMMON_ERROR_FORMAT_EXCEPTION, "exists key:" + key);
			}
		}
		return i;
	}

	@Override
	public <T extends Serializable> boolean setJson(String key, T object) {
		return set(key, JacksonUtil.toJson(object));
	}

	@Override
	public <T extends Serializable> boolean setJson(String key, T object, int seconds) {
		return set(key, JacksonUtil.toJson(object), seconds);
	}

	@Override
	public <T extends Serializable> boolean setJson(String key, T object, Date expire) {
		return set(key, JacksonUtil.toJson(object), expire);
	}

	@Override
	public <T extends Serializable> T getJson(String key, Class<T> clazz) {
		String json = get(key);
		return JacksonUtil.fromJson(json, clazz);
	}

	@Override
	@Async
	public <T extends Serializable> void setAsyn(String key, T object) {
		if (object == null) {
			return;
		}
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key, object);
		memCachedClient.set(key, object);
	}

	@Override
	public long addOrIncr(String key, int incrValue) {
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key, incrValue);
		return memCachedClient.addOrIncr(key, incrValue);
	}

	@Override
	public long addOrDecr(String key, int decrValue) {
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key, decrValue);
		return memCachedClient.addOrDecr(key, decrValue);
	}

	@Override
	public long incr(String key) {
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key);
		return memCachedClient.incr(key);
	}

	@Override
	public long decr(String key) {
		key = namespacedKey(key);
		logger.debug("写缓存 {} {}", key);
		return memCachedClient.decr(key);
	} 

}
